﻿// Decompiled with JetBrains decompiler
// Type: System.Web.Razor.Editor.BackgroundParser
// Assembly: System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// MVID: 682513D6-F37E-48AC-9909-F3EE103CFF14
// Assembly location: D:\Project\Idea\无人机外网\uav\客户端工程\排查工具\bin\Release\System.Web.Razor.dll

using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Web.Razor.Parser.SyntaxTree;
using System.Web.Razor.Text;
using System.Web.Razor.Utils;

namespace System.Web.Razor.Editor
{
  internal class BackgroundParser : IDisposable
  {
    private BackgroundParser.MainThreadState _main;
    private BackgroundParser.BackgroundThread _bg;

    public BackgroundParser(RazorEngineHost host, string fileName)
    {
      this._main = new BackgroundParser.MainThreadState(fileName);
      this._bg = new BackgroundParser.BackgroundThread(this._main, host, fileName);
      this._main.ResultsReady += (EventHandler<DocumentParseCompleteEventArgs>) ((sender, args) => this.OnResultsReady(args));
    }

    public event EventHandler<DocumentParseCompleteEventArgs> ResultsReady;

    public bool IsIdle => this._main.IsIdle;

    public void Start() => this._bg.Start();

    public void Cancel() => this._main.Cancel();

    public void QueueChange(TextChange change) => this._main.QueueChange(change);

    public void Dispose() => this._main.Cancel();

    public IDisposable SynchronizeMainThreadState() => this._main.Lock();

    protected virtual void OnResultsReady(DocumentParseCompleteEventArgs args)
    {
      EventHandler<DocumentParseCompleteEventArgs> resultsReady = this.ResultsReady;
      if (resultsReady == null)
        return;
      resultsReady((object) this, args);
    }

    internal static bool TreesAreDifferent(
      Block leftTree,
      Block rightTree,
      IEnumerable<TextChange> changes)
    {
      return BackgroundParser.TreesAreDifferent(leftTree, rightTree, changes, CancellationToken.None);
    }

    internal static bool TreesAreDifferent(
      Block leftTree,
      Block rightTree,
      IEnumerable<TextChange> changes,
      CancellationToken cancelToken)
    {
      foreach (TextChange change in changes)
      {
        cancelToken.ThrowIfCancellationRequested();
        Span target = leftTree.LocateOwner(change);
        if (target == null)
          return true;
        EditResult editResult = target.EditHandler.ApplyChange(target, change, true);
        target.ReplaceWith(editResult.EditedSpan);
      }
      return !leftTree.EquivalentTo((SyntaxTreeNode) rightTree);
    }

    private abstract class ThreadStateBase
    {
      [Conditional("DEBUG")]
      protected void SetThreadId(int id)
      {
      }

      [Conditional("DEBUG")]
      protected void EnsureOnThread()
      {
      }

      [Conditional("DEBUG")]
      protected void EnsureNotOnThread()
      {
      }
    }

    private class MainThreadState : BackgroundParser.ThreadStateBase, IDisposable
    {
      private CancellationTokenSource _cancelSource = new CancellationTokenSource();
      private ManualResetEventSlim _hasParcel = new ManualResetEventSlim(false);
      private CancellationTokenSource _currentParcelCancelSource;
      private string _fileName;
      private object _stateLock = new object();
      private IList<TextChange> _changes = (IList<TextChange>) new List<TextChange>();

      public MainThreadState(string fileName) => this._fileName = fileName;

      public event EventHandler<DocumentParseCompleteEventArgs> ResultsReady;

      public CancellationToken CancelToken => this._cancelSource.Token;

      public bool IsIdle
      {
        get
        {
          lock (this._stateLock)
            return this._currentParcelCancelSource == null;
        }
      }

      public void Cancel() => this._cancelSource.Cancel();

      public IDisposable Lock()
      {
        Monitor.Enter(this._stateLock);
        return (IDisposable) new DisposableAction((Action) (() => Monitor.Exit(this._stateLock)));
      }

      public void QueueChange(TextChange change)
      {
        lock (this._stateLock)
        {
          if (this._currentParcelCancelSource != null)
            this._currentParcelCancelSource.Cancel();
          this._changes.Add(change);
          this._hasParcel.Set();
        }
      }

      public BackgroundParser.WorkParcel GetParcel()
      {
        this._hasParcel.Wait(this._cancelSource.Token);
        this._hasParcel.Reset();
        lock (this._stateLock)
        {
          this._currentParcelCancelSource = new CancellationTokenSource();
          IList<TextChange> changes = this._changes;
          this._changes = (IList<TextChange>) new List<TextChange>();
          CancellationToken token = this._currentParcelCancelSource.Token;
          return new BackgroundParser.WorkParcel(changes, token);
        }
      }

      public void ReturnParcel(DocumentParseCompleteEventArgs args)
      {
        lock (this._stateLock)
        {
          if (this._currentParcelCancelSource != null)
          {
            this._currentParcelCancelSource.Dispose();
            this._currentParcelCancelSource = (CancellationTokenSource) null;
          }
          if (this._changes.Any<TextChange>())
            return;
        }
        EventHandler<DocumentParseCompleteEventArgs> resultsReady = this.ResultsReady;
        if (resultsReady == null)
          return;
        resultsReady((object) this, args);
      }

      public void Dispose()
      {
        this.Dispose(true);
        GC.SuppressFinalize((object) this);
      }

      protected virtual void Dispose(bool disposing)
      {
        if (!disposing)
          return;
        if (this._currentParcelCancelSource != null)
        {
          this._currentParcelCancelSource.Dispose();
          this._currentParcelCancelSource = (CancellationTokenSource) null;
        }
        this._cancelSource.Dispose();
        this._hasParcel.Dispose();
      }
    }

    private class BackgroundThread : BackgroundParser.ThreadStateBase
    {
      private BackgroundParser.MainThreadState _main;
      private Thread _backgroundThread;
      private CancellationToken _shutdownToken;
      private RazorEngineHost _host;
      private string _fileName;
      private Block _currentParseTree;
      private IList<TextChange> _previouslyDiscarded = (IList<TextChange>) new List<TextChange>();

      public BackgroundThread(
        BackgroundParser.MainThreadState main,
        RazorEngineHost host,
        string fileName)
      {
        this._main = main;
        this._backgroundThread = new Thread(new ThreadStart(this.WorkerLoop));
        this._shutdownToken = this._main.CancelToken;
        this._host = host;
        this._fileName = fileName;
      }

      public void Start() => this._backgroundThread.Start();

      private void WorkerLoop()
      {
        Path.GetFileName(this._fileName);
        try
        {
          while (!this._shutdownToken.IsCancellationRequested)
          {
            BackgroundParser.WorkParcel parcel = this._main.GetParcel();
            if (parcel.Changes.Any<TextChange>())
            {
              try
              {
                DocumentParseCompleteEventArgs args = (DocumentParseCompleteEventArgs) null;
                using (CancellationTokenSource linkedTokenSource = CancellationTokenSource.CreateLinkedTokenSource(this._shutdownToken, parcel.CancelToken))
                {
                  if (!linkedTokenSource.IsCancellationRequested)
                  {
                    List<TextChange> source = this._previouslyDiscarded == null ? parcel.Changes.ToList<TextChange>() : this._previouslyDiscarded.Concat<TextChange>((IEnumerable<TextChange>) parcel.Changes).ToList<TextChange>();
                    TextChange textChange = source.Last<TextChange>();
                    GeneratorResults change = this.ParseChange(textChange.NewBuffer, linkedTokenSource.Token);
                    if (change != null && !linkedTokenSource.IsCancellationRequested)
                    {
                      this._previouslyDiscarded = (IList<TextChange>) null;
                      bool flag = this._currentParseTree == null || BackgroundParser.TreesAreDifferent(this._currentParseTree, change.Document, (IEnumerable<TextChange>) source, parcel.CancelToken);
                      this._currentParseTree = change.Document;
                      args = new DocumentParseCompleteEventArgs()
                      {
                        GeneratorResults = change,
                        SourceChange = textChange,
                        TreeStructureChanged = flag
                      };
                    }
                    else
                      this._previouslyDiscarded = (IList<TextChange>) source;
                  }
                }
                if (args != null)
                  this._main.ReturnParcel(args);
              }
              catch (OperationCanceledException ex)
              {
              }
            }
            else
              Thread.Yield();
          }
        }
        catch (OperationCanceledException ex)
        {
        }
        finally
        {
          this._main.Dispose();
        }
      }

      private GeneratorResults ParseChange(
        ITextBuffer buffer,
        CancellationToken token)
      {
        RazorTemplateEngine razorTemplateEngine = new RazorTemplateEngine(this._host);
        buffer.Position = 0;
        try
        {
          return razorTemplateEngine.GenerateCode(buffer, (string) null, (string) null, this._fileName, new CancellationToken?(token));
        }
        catch (OperationCanceledException ex)
        {
          return (GeneratorResults) null;
        }
      }
    }

    private class WorkParcel
    {
      public WorkParcel(IList<TextChange> changes, CancellationToken cancelToken)
      {
        this.Changes = changes;
        this.CancelToken = cancelToken;
      }

      public CancellationToken CancelToken { get; private set; }

      public IList<TextChange> Changes { get; private set; }
    }
  }
}
